package Verwaltung.Datencontroler;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JOptionPane;

import Verwaltung.Daten.Aktivitaet;
import Verwaltung.Daten.Betreuer;
import Verwaltung.Daten.Klasse;
import Verwaltung.Daten.Lehrer;
import Verwaltung.Daten.Interfaces.IKlasse;
import Verwaltung.Daten.Interfaces.ILehrkraft;

public class Datencontroler {

	private Connection dbConnect2 = null;

	/**
	 * Erstellt einen neuen Datencontroler
	 */
	public Datencontroler() {

		getConnection();
	}

	public Connection getConnection() {

		if (dbConnect2 == null) {
			try {
				dbConnect2 = DriverManager.getConnection(
						"jdbc:postgresql://127.0.0.1:5432/mdo", "postgres",
						"sql");
			} catch (final SQLException e) {

				System.out.print(e.toString());
				System.out.print(" - SQL-Status: " + e.getSQLState());
				System.out.println(" - ErrorCode: " + e.getErrorCode());
				e.printStackTrace();

				JOptionPane.showMessageDialog(null,
						"Fehler beim Verbinden zur DB");
			}
		}
		return dbConnect2;
	}

	/**
	 * schreibt ein Objekt in die DB
	 * 
	 * @param objekt
	 *            Objekt welches gespeichert werden soll
	 */
	public void schreibeInDB(final IDBObjekt objekt) {

		if (objekt instanceof Aktivitaet) {
			final String name = ((Aktivitaet) objekt).getName();
			final int dauer = ((Aktivitaet) objekt).getDauer();
			final int startstunde = ((Aktivitaet) objekt).getStartHour();
			final int startminute = ((Aktivitaet) objekt).getStartMinute();
			final String day = ((Aktivitaet) objekt).getWochentag();
			final List<IKlasse> klassen = ((Aktivitaet) objekt).getKlassen();
			final List<ILehrkraft> lehrkraefte = ((Aktivitaet) objekt)
					.getLehrkraefte();
			try {
				final PreparedStatement sqlBefehl = getConnection()
						.prepareStatement(
								"INSERT INTO aktivitaet (name, dauer, startstunde, wochentag, startminute) VALUES (?,?,?,?,?) RETURNING id");
				sqlBefehl.setString(1, name);
				sqlBefehl.setInt(2, dauer);
				sqlBefehl.setInt(3, startstunde);
				sqlBefehl.setString(4, day);
				sqlBefehl.setInt(5, startminute);
				final ResultSet rset = sqlBefehl.executeQuery();

				rset.next();

				final int aktiId = rset.getInt("id");

				sqlBefehl.close();

				((Aktivitaet) objekt).setId(aktiId);

				final PreparedStatement sqlBefehl2 = getConnection()
						.prepareStatement(
								"INSERT INTO aktivitaet_lehrer (id_aktivitaet, id_lehrer) VALUES (?,?)");
				for (final ILehrkraft lehrkraft : lehrkraefte) {
					sqlBefehl2.setInt(1, aktiId);
					sqlBefehl2.setInt(2, lehrkraft.getID());
					sqlBefehl2.executeUpdate();
				}

				sqlBefehl2.close();

				final PreparedStatement sqlBefehl3 = getConnection()
						.prepareStatement(
								"INSERT INTO aktivitaet_klasse (id_aktivitaet, id_klasse) VALUES (?,?)");
				for (final IKlasse klasse : klassen) {
					sqlBefehl3.setInt(1, aktiId);
					sqlBefehl3.setInt(2, ((Klasse) klasse).getId());
					sqlBefehl3.executeUpdate();
				}

				sqlBefehl3.close();
			} catch (final SQLException e) {

				System.out.print(e.toString());
				System.out.print(" - SQL-Status: " + e.getSQLState());
				System.out.println(" - ErrorCode: " + e.getErrorCode());

				e.printStackTrace();
			}
		} else if (objekt instanceof Betreuer || objekt instanceof Lehrer) {

			final ILehrkraft lehr = (ILehrkraft) objekt;

			final String name = lehr.getName();
			final String loginname = lehr.getLoginName();
			final int wochenstunden = lehr.getWochenstunden();
			final boolean darfunterrichten = lehr.darfUnterrichten();
			final String passwort = lehr.getPassword();
			final int plvl = lehr.getPermissionLvl();

			try {
				final PreparedStatement sqlBefehl3 = getConnection()
						.prepareStatement(
								"INSERT INTO lehrer (name, loginname, passwort, wochenstunden, darfunterrichten, permissionlvl) VALUES (?,?,?,?,?,?)");
				sqlBefehl3.setString(1, name);
				sqlBefehl3.setString(2, loginname);
				sqlBefehl3.setString(3, passwort);
				sqlBefehl3.setInt(4, wochenstunden);
				sqlBefehl3.setBoolean(5, darfunterrichten);
				sqlBefehl3.setInt(6, plvl);
				sqlBefehl3.executeUpdate();

				sqlBefehl3.close();
			} catch (final SQLException e) {
				System.out.print(e.toString());
				System.out.print(" - SQL-Status: " + e.getSQLState());
				System.out.println(" - ErrorCode: " + e.getErrorCode());
				e.printStackTrace();
			}

		} else if (objekt instanceof Klasse) {
			final String name = ((Klasse) objekt).getName();

			try {
				final PreparedStatement sqlBefehl4 = getConnection()
						.prepareStatement(
								"INSERT INTO klasse (name) VALUES (?)");
				sqlBefehl4.setString(1, name);
				sqlBefehl4.executeUpdate();

				sqlBefehl4.close();

			} catch (final SQLException e) {
				System.out.print(e.toString());
				System.out.print(" - SQL-Status: " + e.getSQLState());
				System.out.println(" - ErrorCode: " + e.getErrorCode());
				e.printStackTrace();
			}
		} else {
			throw new IllegalArgumentException("Object nicht bekannt "
					+ objekt.toString());
		}
	}

	/**
	 * entfernt ein objekt aus der Db
	 * 
	 * @param objekt
	 *            Objekt welches aus der DB entfernt werden soll
	 */
	public void removeVonDB(final IDBObjekt objekt) {

		if (objekt instanceof Aktivitaet) {
			try {
				final int akid = ((Aktivitaet) objekt).getId();
				final PreparedStatement sqlBefehl = getConnection()
						.prepareStatement(
								"DELETE from aktivitaet WHERE id=" + akid);
				sqlBefehl.executeUpdate();
				sqlBefehl.close();

				final PreparedStatement sqlBefehl2 = getConnection()
						.prepareStatement(
								"DELETE from aktivitaet_lehrer WHERE id_aktivitaet="
										+ akid);
				sqlBefehl2.executeUpdate();
				sqlBefehl2.close();

				final PreparedStatement sqlBefehl3 = getConnection()
						.prepareStatement(
								"DELETE from aktivitaet_klasse WHERE id_aktivitaet="
										+ akid);
				sqlBefehl3.executeUpdate();
				sqlBefehl3.close();
			} catch (final SQLException e) {

				System.out.print(e.toString());
				System.out.print(" - SQL-Status: " + e.getSQLState());
				System.out.println(" - ErrorCode: " + e.getErrorCode());
				e.printStackTrace();
			}
		} else if (objekt instanceof ILehrkraft) {

			final int lehrkraftId = ((ILehrkraft) objekt).getID();
			try {
				final PreparedStatement sqlBefehl6 = getConnection()
						.prepareStatement(
								"DELETE from lehrer WHERE id=" + lehrkraftId);
				sqlBefehl6.executeUpdate();
				sqlBefehl6.close();

				final PreparedStatement sqlBefehl2 = getConnection()
						.prepareStatement(
								"DELETE from aktivitaet_lehrer WHERE id_lehrer="
										+ lehrkraftId);
				sqlBefehl2.executeUpdate();

				sqlBefehl2.close();

			} catch (final SQLException e) {
				e.printStackTrace();
				System.out.print(e.toString());
				System.out.print(" - SQL-Status: " + e.getSQLState());
				System.out.println(" - ErrorCode: " + e.getErrorCode());
				e.printStackTrace();
			}

		} else if (objekt instanceof Klasse) {

			final Klasse klasse = (Klasse) objekt;
			try {
				final PreparedStatement sqlBefehl7 = getConnection()
						.prepareStatement(
								"DELETE from klasse WHERE id=" + klasse.getId());
				sqlBefehl7.executeUpdate();
				sqlBefehl7.close();

				final PreparedStatement sqlBefehl3 = getConnection()
						.prepareStatement(
								"DELETE from aktivitaet_klasse WHERE id_klasse="
										+ klasse.getId());
				sqlBefehl3.executeUpdate();
				sqlBefehl3.close();

			} catch (final SQLException e) {

				System.out.print(e.toString());
				System.out.print(" - SQL-Status: " + e.getSQLState());
				System.out.println(" - ErrorCode: " + e.getErrorCode());
				e.printStackTrace();
			}

		} else {
			System.out.println("Error");
		}
	}

	/**
	 * Aktualisiert die Attribute eines Objektes in der Datenbank
	 * 
	 * @param objekt
	 *            Objekt, dessen Attribute aktualisiert werden soll
	 */
	public void updateDB(final IDBObjekt objekt) {

		try {

			if (objekt instanceof ILehrkraft) {

				final ILehrkraft lehr = (ILehrkraft) objekt;

				final PreparedStatement sqlBefehl3 = getConnection()
						.prepareStatement(
								"UPDATE lehrer SET name = ?, loginname = ?, passwort = ?, wochenstunden = ?, darfunterrichten = ?, permissionlvl = ? WHERE id = ?");
				sqlBefehl3.setString(1, lehr.getName());
				sqlBefehl3.setString(2, lehr.getLoginName());
				sqlBefehl3.setString(3, lehr.getPassword());
				sqlBefehl3.setInt(4, lehr.getWochenstunden());
				sqlBefehl3.setBoolean(5, lehr.darfUnterrichten());
				sqlBefehl3.setInt(6, lehr.getPermissionLvl());
				sqlBefehl3.setInt(7, lehr.getID());
				sqlBefehl3.executeUpdate();

				sqlBefehl3.close();

			} else if (objekt instanceof Klasse) {

				final Klasse klass = (Klasse) objekt;
				final PreparedStatement sqlBefehl4 = getConnection()
						.prepareStatement(
								"UPDATE klasse SET name = ? WHERE id = ?");
				sqlBefehl4.setString(1, klass.getName());
				sqlBefehl4.setInt(2, klass.getId());
				sqlBefehl4.executeUpdate();

				sqlBefehl4.close();

			} else if (objekt instanceof Aktivitaet) {

				throw new IllegalArgumentException(
						"Aktivitäten bitte lsöchen und neu einfügen");
			} else {

				throw new IllegalArgumentException("Objekt nicht unterstützt. "
						+ objekt);
			}

		} catch (final Exception e) {
			e.printStackTrace();
		}

	}

	/**
	 * Gibt alle Objekte aus der Datenbank zurück
	 * 
	 * @return Liste alles Objekte aus der DB
	 */
	public List<IDBObjekt> getAlleDBObjekte() {
		final List<IDBObjekt> list = new ArrayList<IDBObjekt>();

		try {

			final PreparedStatement sqlBefehl = getConnection()
					.prepareStatement("SELECT " + "* " + "FROM aktivitaet");
			final ResultSet sqlErgebnis = sqlBefehl.executeQuery();
			while (sqlErgebnis.next()) {
				final String aktName = sqlErgebnis.getString("name");
				final String aktWochentag = sqlErgebnis.getString("wochentag");
				final int aktStartStunde = sqlErgebnis.getInt("startstunde");
				final int aktStartMinute = sqlErgebnis.getInt("startminute");
				final int aktDauer = sqlErgebnis.getInt("dauer");
				final int id = sqlErgebnis.getInt("id");

				final Aktivitaet akti = new Aktivitaet(aktName, aktWochentag,
						aktStartStunde, aktStartMinute, aktDauer);
				akti.setId(id);

				final PreparedStatement sqlBefehl5 = getConnection()
						.prepareStatement(
								"SELECT "
										+ "* "
										+ "FROM aktivitaet_lehrer Where id_aktivitaet="
										+ akti.getId());
				final ResultSet sqlErgebnis5 = sqlBefehl5.executeQuery();
				while (sqlErgebnis5.next()) {
					akti.addLehrkraft(getLehrerById(sqlErgebnis5
							.getInt("id_lehrer")));
				}
				sqlBefehl5.close();

				final PreparedStatement sqlBefehl8 = getConnection()
						.prepareStatement(
								"SELECT "
										+ "* "
										+ "FROM aktivitaet_klasse Where id_aktivitaet="
										+ akti.getId());
				final ResultSet sqlErgebnis8 = sqlBefehl8.executeQuery();
				while (sqlErgebnis8.next()) {

					akti.addKlasse(getKlasseByID(sqlErgebnis8
							.getInt("id_klasse")));

				}
				sqlBefehl8.close();
				list.add(akti);
			}

			sqlBefehl.close();

			// Lehrkräfte

			final PreparedStatement sqlBefehl2 = getConnection()
					.prepareStatement("SELECT id FROM lehrer");
			final ResultSet sqlErgebnis2 = sqlBefehl2.executeQuery();
			while (sqlErgebnis2.next()) {
				list.add(getLehrerById(sqlErgebnis2.getInt("id")));
			}
			sqlBefehl2.close();

			final PreparedStatement sqlBefehl3 = getConnection()
					.prepareStatement("SELECT " + "* " + "FROM klasse");
			final ResultSet sqlErgebnis3 = sqlBefehl3.executeQuery();
			while (sqlErgebnis3.next()) {
				final String klasname = sqlErgebnis3.getString("name");
				final Klasse klas = new Klasse(klasname);
				klas.setId(sqlErgebnis3.getInt("id"));
				list.add(klas);
			}
			sqlBefehl3.close();

		} catch (final SQLException e) {
			e.printStackTrace();
			System.out.print(e.toString());
			System.out.print(" - SQL-Status: " + e.getSQLState());
			System.out.println(" - ErrorCode: " + e.getErrorCode());
			e.printStackTrace();
		}
		return list;
	}

	/**
	 * Gibt eine Lehrkraft anhand einer ID zurück
	 * 
	 * @param pId
	 *            ID nach der gesucht werden soll
	 * @return gefundene Lehrkraft
	 */
	private ILehrkraft getLehrerById(final int pId) {

		try {

			final PreparedStatement sqlBefehl = getConnection()
					.prepareStatement(
							"SELECT " + "* " + "FROM lehrer where id = " + pId
									+ "");
			final ResultSet sqlErgebnis = sqlBefehl.executeQuery();
			while (sqlErgebnis.next()) {
				final int id = sqlErgebnis.getInt("id");
				final String login = sqlErgebnis.getString("loginname");
				final String LehrerName = sqlErgebnis.getString("name");
				final String lpass = sqlErgebnis.getString("passwort");
				final int lwochenstunden = sqlErgebnis.getInt("wochenstunden");
				final int lpermission = sqlErgebnis.getInt("permissionLvl");
				final boolean darfunterrichten = sqlErgebnis
						.getBoolean("darfunterrichten");

				if (darfunterrichten) {
					final Lehrer lehrer = new Lehrer(login, lwochenstunden,
							LehrerName, lpass, lpermission);
					lehrer.setId(id);
					return lehrer;
				} else {

					final Betreuer betreuer = new Betreuer(login,
							lwochenstunden, LehrerName, lpass, lpermission);
					betreuer.setId(id);
					return betreuer;
				}
			}
			sqlErgebnis.close(); // Ergebnismenge schliessen

		} catch (final SQLException e) {
			e.printStackTrace();
			System.out.print(e.toString());
			System.out.print(" - SQL-Status: " + e.getSQLState());
			System.out.println(" - ErrorCode: " + e.getErrorCode());
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Versucht die Person einzuloggen mit gegebenem Namen und Passwort.
	 * 
	 * @param loginName
	 *            Name mit dem sich die Person einloggen will
	 * @param loginPasswort
	 *            Passwort mit dem sich die Person einloggen will
	 * @return true wenn login erfolgreich, false wenn login fehlgeschlagen
	 */
	public boolean login(final String loginName, final String loginPasswort) {

		try {

			final PreparedStatement sqlBefehl1 = getConnection()
					.prepareStatement("SELECT " + "* " + "FROM lehrer");

			final ResultSet sqlErgebnis1 = sqlBefehl1.executeQuery();
			String sqlLehrerLogin = null;
			String sqlLehrerPass = null;
			while (sqlErgebnis1.next()) {
				sqlLehrerLogin = sqlErgebnis1.getString("loginname");
				sqlLehrerPass = sqlErgebnis1.getString("passwort");
				if (sqlLehrerLogin.equals(loginName)
						&& sqlLehrerPass.equals(loginPasswort)) {
					return true;
				}
			}

			sqlErgebnis1.close(); // Ergebnismenge schliessen

			return false;

		} catch (final SQLException e) {
			e.printStackTrace();
			System.out.print(e.toString());
			System.out.print(" - SQL-Status: " + e.getSQLState());
			System.out.println(" - ErrorCode: " + e.getErrorCode());
		}
		return false;
	}

	/**
	 * Gibt eine Aktivität anhand einer ID zurück
	 * 
	 * @param pID
	 *            ID nach der gesucht werden soll
	 * @return Die gefundene Aktivität
	 */
	public Aktivitaet getAktivitaetByID(final int pID) {
		final int aid = pID;
		try {

			final PreparedStatement sqlBefehl = getConnection()
					.prepareStatement(
							"SELECT " + "* " + "FROM aktivitaet where id ="
									+ aid);
			final ResultSet sqlErgebnis = sqlBefehl.executeQuery();
			while (sqlErgebnis.next()) {
				final String aname = sqlErgebnis.getString("name");
				final String awochentag = sqlErgebnis.getString("wochentag");
				final int astartstunde = sqlErgebnis.getInt("startstunde");
				final int astartminute = sqlErgebnis.getInt("startminute");
				final int adauer = sqlErgebnis.getInt("dauer");
				final Aktivitaet a = new Aktivitaet(aname, awochentag,
						astartstunde, astartminute, adauer);
				a.setId(pID);

				return a;
			}
			sqlErgebnis.close(); // Ergebnismenge schliessen

		} catch (final SQLException e) {

			System.out.print(e.toString());
			System.out.print(" - SQL-Status: " + e.getSQLState());
			System.out.println(" - ErrorCode: " + e.getErrorCode());
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Sucht eine Lehrkraft anhand eines loginnamens
	 * 
	 * @param pLoginName
	 *            Loginname nach dem gesucht werden soll
	 * @return
	 */
	public ILehrkraft getLehrkraftByLoginName(final String pLoginName) {
		final String lname = pLoginName;

		try {
			final PreparedStatement sqlBefehl = getConnection()
					.prepareStatement(
							"SELECT " + "* "
									+ "FROM lehrer where loginname = '" + lname
									+ "'");
			final ResultSet sqlErgebnis = sqlBefehl.executeQuery();
			while (sqlErgebnis.next()) {
				final int id = sqlErgebnis.getInt("id");
				final String login = sqlErgebnis.getString("loginname");
				final String LehrerName = sqlErgebnis.getString("name");
				final String lpass = sqlErgebnis.getString("passwort");
				final int lwochenstunden = sqlErgebnis.getInt("wochenstunden");
				final int lpermission = sqlErgebnis.getInt("permissionLvl");
				final boolean darfunterrichten = sqlErgebnis
						.getBoolean("darfunterrichten");

				if (darfunterrichten) {
					final Lehrer lehrer = new Lehrer(login, lwochenstunden,
							LehrerName, lpass, lpermission);
					lehrer.setId(id);
					return lehrer;
				} else {

					final Betreuer betreuer = new Betreuer(login,
							lwochenstunden, LehrerName, lpass, lpermission);
					betreuer.setId(id);
					return betreuer;
				}
			}
			sqlErgebnis.close(); // Ergebnismenge schliessen

		} catch (final SQLException e) {
			e.printStackTrace();
			System.out.print(e.toString());
			System.out.print(" - SQL-Status: " + e.getSQLState());
			System.out.println(" - ErrorCode: " + e.getErrorCode());
		}
		return null;
	}

	/**
	 * Sucht in der DB nach einer Klasse anhand eines Namens
	 * 
	 * @param pName
	 *            Name, nach dem gesucht werden soll
	 * @return gefundene Klasse
	 */
	public Klasse getKlasseByName(final String pName) {
		final String kname = pName;
		try {

			final PreparedStatement sqlBefehl = getConnection()
					.prepareStatement(
							"SELECT " + "* " + "FROM klasse where name = '"
									+ kname + "'");
			final ResultSet sqlErgebnis = sqlBefehl.executeQuery();
			while (sqlErgebnis.next()) {
				final String klassName = sqlErgebnis.getString("name");
				final int id = sqlErgebnis.getInt("id");
				final Klasse k = new Klasse(klassName);
				k.setId(id);
				return k;
			}
			sqlErgebnis.close(); // Ergebnismenge schliessen

		} catch (final SQLException e) {
			e.printStackTrace();
			System.out.print(e.toString());
			System.out.print(" - SQL-Status: " + e.getSQLState());
			System.out.println(" - ErrorCode: " + e.getErrorCode());
		}
		return null;
	}

	/**
	 * Gibt eine Klasse anhand der ID zurück
	 * 
	 * @param pId
	 *            ID der Klasse
	 * @return gefundene Klasse
	 */
	public Klasse getKlasseByID(final int pId) {

		try {
			final PreparedStatement sqlBefehl = getConnection()
					.prepareStatement(
							"SELECT " + "* " + "FROM klasse where id = " + pId
									+ "");
			final ResultSet sqlErgebnis = sqlBefehl.executeQuery();
			while (sqlErgebnis.next()) {
				final String klassName = sqlErgebnis.getString("name");
				final int id = sqlErgebnis.getInt("id");
				final Klasse k = new Klasse(klassName);
				k.setId(id);
				return k;
			}
			sqlErgebnis.close(); // Ergebnismenge schliessen

		} catch (final SQLException e) {
			e.printStackTrace();
			System.out.print(e.toString());
			System.out.print(" - SQL-Status: " + e.getSQLState());
			System.out.println(" - ErrorCode: " + e.getErrorCode());
		}
		return null;
	}
}